packageentity;importjava.util.List;importjavax.persistence.EntityManager;importjavax.persistence.EntityManagerFactory;importjavax.persistence.NoResultException;importjavax.persistence.NonUniqueResultException;importjavax.persistence.Persistence;importorg.apache.log4j.BasicConfigurator;importorg.apache.log4j.Level;importorg.apache.log4j.Logger;importorg.hibernate.hql.ast.QuerySyntaxException;importorg.junit.After;importorg.junit.Assert;importorg.junit.Before;importorg.junit.BeforeClass;importorg.junit.Test;publicclass QueriesTest extends Assert {private EntityManagerFactory emf;private EntityManager em;
@BeforeClass
publicstaticvoid initLogger(){// Produce minimal output.
BasicConfigurator.configure();// Comment this line to see a lot of initialization// status logging.Logger.getLogger("org").setLevel(Level.ERROR);}
@Before
publicvoid initEmfAndEm(){
emf = Persistence.createEntityManagerFactory("examplePersistenceUnit");
em = emf.createEntityManager();}
@After
publicvoid closeEmAndEmf(){
em.close();
emf.close();}
@Test(expected = IllegalArgumentException.class)publicvoid unsuccessfulWithBadExceptionThrownEmptyQuery(){Logger.getLogger("org").setLevel(Level.FATAL);try{// This one got me and I wasted several hours looking at// the wrong rabbit hole. I was paying attention to the// error but not looking at the line that was failing.
em.createQuery("");}finally{Logger.getLogger("org").setLevel(Level.ERROR);}}
@Test
publicvoid unsuccessfulUnknownClass(){try{// This fails because IncorrectClassName is not registered.// If we were using JEE rather than JSE, this implies that// there is no class named IncorrectClassName anywhere// in the class path that has the @Entity annotation (or// is mapped via XML).
em.createQuery("from IncorrectClassName");}catch(IllegalArgumentException e){
assertEquals(e.getCause().getClass(), QuerySyntaxException.class);
assertEquals(("org.hibernate.hql.ast.QuerySyntaxException: " +
"IncorrectClassName is not mapped " +
"[from IncorrectClassName]"),
e.getMessage());}}
@Test
publicvoid successfulNotUsingSelect(){
em.createQuery("from Person").getResultList();}
@Test
publicvoid successfulSingleResult(){
clearPersonTable();
insertPerson();// This query has the potential to fail since it is returning// all Person entities, but it does not because I've only// inserted one.final Person p = (Person) em.createQuery("from Person")
.getSingleResult();
assertEquals("Brett", p.getFirstName());}
@Test(expected = NoResultException.class)publicvoid unsuccessfulSingleResultNoEntries(){// Notice that if we just want to get all rows from// an Entity's table, this is the minimal query
em.createQuery("from Person").getSingleResult();}
@Test(expected = NonUniqueResultException.class)publicvoid unsuccessfulSingleResultTooManyEntries(){
insertPerson();
insertPerson();// This will fail because we expect a single result// but in fact there are 2 results returned.
em.createQuery("from Person").getSingleResult();}
@Test
publicvoid successfulFindByPrimaryKey(){finalint personKey = insertPerson();// Note, we provide Person.class as the first parameter// so the underling method, which is a generic method// can return the right type. Also, because we provide// the class, the only thing that might happen is that// we do not find a Person in the Person table. It is// not possible for find to return the wrong type since// it picks up its table name from the Person.class.final Person p = em.find(Person.class, personKey);
assertEquals("Brett", p.getFirstName());}
@Test
publicvoid unsuccessfulLookupByKeyNothingFound(){
clearPersonTable();// Note the lack of an "expected = ..." in the @Test// annotation. Find returns null if it cannot find// the object with the provided key. It does not throw// an exception.final Person p = em.find(Person.class, -42);
assertNull(p);}
@Test
publicvoid successfulSearchUsingQueryParameter(){
insertPerson();// Note, the return type of this method is List<?>, not List<Person>.// See the next method for the other option...finalList<?> list = em.createQuery("from Person where firstName = ?1")
.setParameter(1, "Brett").getResultList();
assertEquals(1, list.size());}/**
* This method does the same thing as the one above it. But to avoid a
* warning about type safety I am using the annotation
*
* @SuppressWarnings. When you start writing Data Access Objects, you'll
* probably go this route.
*
* For those of you who know generic parameters, it is not possible to get
* this to work in a type-safe manner due to "erasure." Look up "java
* generics erasure".
* http://today.java.net/pub/a/today/2003/12/02/explorations.html
*/
@SuppressWarnings("unchecked")
@Test
publicvoid theOtherOption(){
insertPerson();finalList<Person> list = em.createQuery("from Person where firstName = ?1").setParameter(1, "Brett")
.getResultList();
assertEquals(1, list.size());}
@Test
publicvoid successfulSameInMemoryObjectsReturnedFromDifferntQueries(){finalint personKey = insertPerson();final Person pByKey = em.find(Person.class, personKey);final Person pByWhere = (Person) em.createQuery("SELECT p from Person p where firstName='Brett'")
.getSingleResult();// are these objects == (same object in memory)?
assertSame(pByKey, pByWhere);}
@Test(expected = IllegalArgumentException.class)publicvoid unsuccessfulCaseWrongOnClass(){// fails because we're naming a class, not a table// So instead of PERSON we must use Person
em.createQuery("from PERSON").getSingleResult();}
@Test(expected = IllegalArgumentException.class)publicvoid unsuccessfulWrongFieldNameUsedInWhereWithNamedPerson(){
insertPerson();// failes because the attribute is not called FirstName but// is instead called firstName (first letter should be// lower case following the java beans standard.
em.createQuery("from Person p where p.FirstName='Brett'");}
@Test
publicvoid successfulColumnNameNotCaseSensitive(){
insertPerson();// Note that we are not qualifying FirstName with p,// so it is interpreted as a column name rather than// a fieldName that must follow java beans naming// conventions
em.createQuery("from Person p where FirstName='Brett'").getResultList();}
@Test(expected = IllegalArgumentException.class)publicvoid unsuccessfulSettingParamterWithWrongIndex(){// Indexes are 1-based, not 0-based.
em.createQuery("from Person p where FirstName='Brett'").setParameter(0,
"Brett");}
@Test(expected = IllegalArgumentException.class)publicvoid unsuccessfulSettingParameterWhereThereAreNone(){// There's no parameter here, this simply fails
em.createQuery("from Person p where FirstName='Brett'").setParameter(1,
"Brett");}
@Test(expected = IllegalArgumentException.class)publicvoid unsuccessfulDoNotQuoteStringParameters(){
em.createQuery("from Person p where FirstName='?1'").setParameter(1,
"Brett");}/**
* Even though we **begin** a transaction, we never commit it. So when we
* close the em, nothing that was flushed will actually be committed.
*
*/privateint insertPerson(){final Address a1 = new Address("A Rd.", "", "Dallas", "TX", "75001");final Person p1 = new Person("Brett", 'L', "Schuchert", a1);if(!em.getTransaction().isActive()){
em.getTransaction().begin();}
em.persist(p1);return p1.getId();}privatevoid clearPersonTable(){if(!em.getTransaction().isActive()){
em.getTransaction().begin();}
em.createQuery("delete from Person").executeUpdate();}}